package pl.wroc.pwr.docs.repos.controller;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.hibernate.search.errors.EmptyQueryException;
import org.hibernate.search.jpa.FullTextQuery;
import org.hibernate.search.query.facet.Facet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import pl.wroc.pwr.docs.repos.domain.Document;
import pl.wroc.pwr.docs.repos.service.DocumentService;
import pl.wroc.pwr.docs.repos.utils.PartUtils;
import pl.wroc.pwr.docs.repos.web.Message;
import pl.wroc.pwr.docs.repos.web.Message.STATUS;
import pl.wroc.pwr.docs.repos.web.FiltrForm;

@Controller
public class DocumentController {
	// To zdecydowannie nie może być pole w kontolerze !
	// przy wielu wątkach będą się dziwne rzeczy dziać
	FullTextQuery fullTextQuery;
	
	
	@Autowired
	private DocumentService documentService;
	
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String index(){
		return "redirect:/documents";
	}
	
	@RequestMapping(value = "/document/add", method = RequestMethod.POST)
	public String addDocument(HttpServletRequest request, 
	                          @ModelAttribute ArrayList<Message> messages, 
	                          RedirectAttributes attrs) throws IOException, ServletException {
		
		for (Part file : request.getParts()) {
		
			if(file.getSize() == 0){
				messages.add(new Message(Message.STATUS.WARN,"Pusty plik."));
			}
			else {
				String filename = PartUtils.getFileName(file);
	
					if(filename == null)
						continue;
			
				try {
					documentService.add(filename, file.getInputStream());
					messages.add(new Message(Message.STATUS.SUCCESS,"Dodanie pliku powiodło się."));
				} catch (Exception e) {
					e.printStackTrace();
					messages.add(new Message(Message.STATUS.ERROR,"Dodanie pliku nie powiodło się."));
				}
			}
			attrs.addFlashAttribute("messages", messages);
		}
		
		return "redirect:/documents";
	}
	
	@RequestMapping(value = "/document/{id}/show")
	public String getDocument(@PathVariable int id, Model model) throws IOException {
		model.addAttribute("document", documentService.getDocument(id));
		model.addAttribute("terms", documentService.getTermsSortedByFrequency(id));
		return "Document";
	}
	
	@RequestMapping(value = "/document/{id}/update")
	public String updateDocument(@RequestParam(value = "title") String title, @RequestParam(value = "author") String author, @RequestParam(value = "created") String created, @PathVariable int id) {
		DateFormat dateFrm = new SimpleDateFormat("yyyy-MM-dd");
	    java.util.Date myDate = new java.util.Date();
	    java.sql.Date sqlDate;
	    
	    Document doc = documentService.getDocument(id);
	    
		try
		{
			myDate = dateFrm.parse(created);
			sqlDate = new java.sql.Date(myDate.getTime());
			doc.setCreated(sqlDate);
		}
		catch (Exception e)
		{
			System.out.println("Bledny format daty");
		}

		doc.setTitle(title);
		doc.setAuthor(author);
		documentService.save(doc);
		return "redirect:/document/{id}/show";
	}
	
	@RequestMapping(value = "/document/{id}/delete")
	public String deleteDocument(@PathVariable int id, RedirectAttributes attrs) {
		documentService.delete(id);
		return "redirect:/documents";
	}
	
	@RequestMapping(value = "/document/{id}/download")
	public void downloadDocument(@PathVariable int id, HttpServletResponse res) {
		Document doc = documentService.getDocument(id);
		res.addHeader("Content-Disposition",  "attachment; filename=\"" + doc.getFilename() + "\"");
		try {
			IOUtils.copy(new ByteArrayInputStream(doc.getBinaryData()), res.getOutputStream());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@RequestMapping(value = "/documents", method = RequestMethod.GET)
	public String searchDocuments(Model model,
							   @ModelAttribute("filtrForm") ArrayList<FiltrForm> filtrForm,
	                           @ModelAttribute("messages") ArrayList<Message> messages,
	                           @RequestParam(value="p", defaultValue = "1") int pageNumber,
	                           @RequestParam(value="q", required = false) String searchQuery,
	                           @RequestParam(value="format", required = false) List<String> formats) {
		if(formats==null){
			
			fullTextQuery = documentService.buildQuery(searchQuery);
			Page<Document> page = documentService.search(pageNumber, fullTextQuery);
			List<Facet> facet = documentService.getFacets(fullTextQuery);
							
			
			for(Facet fa : facet) {
				FiltrForm fForm;
				fForm = new FiltrForm(fa.getValue(), fa.getCount());
			
				filtrForm.add(fForm);
			}
			
			int offset = 3;
			int minPage = Math.max(page.getNumber() - offset , 0);
			int maxPage = Math.min(page.getNumber() + offset, page.getTotalPages() - 1);
			model.addAttribute("page", page);
			model.addAttribute("maxPage", maxPage);
			model.addAttribute("minPage", minPage);
			model.addAttribute("formatFacet", facet);
			
			int total = (int) page.getTotalElements();
			
			if(StringUtils.isNotBlank(searchQuery)){
				try{
					
					model.addAttribute("q", searchQuery);
					
					Message message;
					
					switch(total){
						case 0:
							message = new Message(STATUS.WARN, "Nie znaleziono dokumentów spełniających podane kryteria.");
							break;
						case 1:
							message = new Message(STATUS.INFO, "Znaleziono " + total + " dokument.");
							break;
						case 2:
						case 3:
						case 4:
							message = new Message(STATUS.INFO, "Znaleziono " + total + " dokumenty.");
							break;
						default:
							message = new Message(STATUS.INFO, "Znaleziono " + total + " dokumentów.");
							break;
					}
					
					messages.add(message);
				}
				catch(EmptyQueryException ex){
					messages.add(new Message(STATUS.WARN, "Kryteria zbyt ogólne."));
				}
				
			}
			else{
							
				if(total == 0){
					messages.add(new Message(STATUS.WARN, "Nie dodano żadnych dokuementów."));
				}
				else{
					messages.add(new Message(STATUS.INFO, "Ostatnio dodane dokumenty."));
				}
			}
		}
		else
		{
			try{
				
				fullTextQuery = documentService.filtrQuery(fullTextQuery, formats);
				Page<Document> page = documentService.search(pageNumber, fullTextQuery);
				fullTextQuery = documentService.resetQuery(fullTextQuery);
				List<Facet> facet = documentService.getFacets(fullTextQuery);
				
				for(Facet fa : facet) {
					FiltrForm fForm;
					fForm = new FiltrForm(fa.getValue(), fa.getCount());
					
					for(String format: formats) {
						System.out.println(format+" " +fa.getValue());
						if(fa.getValue() == format)
							fForm.setChecked();
					}
					
					filtrForm.add(fForm);
				}
				
				int offset = 3;
				int minPage = Math.max(page.getNumber() - offset , 0);
				int maxPage = Math.min(page.getNumber() + offset, page.getTotalPages() - 1);
				model.addAttribute("page", page);
				model.addAttribute("maxPage", maxPage);
				model.addAttribute("minPage", minPage);
				model.addAttribute("q", searchQuery);
				model.addAttribute("formatFacet", facet);
				model.addAttribute("formats", formats);
				
				int total = (int) page.getTotalElements();
				Message message;
						
				switch(total){
					case 0:
						message = new Message(STATUS.WARN, "Nie znaleziono dokumentów spełniających podane kryteria.");
						break;
					case 1:
						message = new Message(STATUS.INFO, "Znaleziono " + total + " dokument.");
						break;
					case 2:
					case 3:
					case 4:
						message = new Message(STATUS.INFO, "Znaleziono " + total + " dokumenty.");
						break;
					default:
						message = new Message(STATUS.INFO, "Znaleziono " + total + " dokumentów.");
						break;
				}
				
				messages.add(message);
			}
			catch(EmptyQueryException ex){
				messages.add(new Message(STATUS.WARN, "Kryteria zbyt ogólne."));
			}
		}
		
		return "Documents";
	}
}
